View Javadoc
1   package org.apache.maven.surefire.junitcore.pc;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.surefire.report.ConsoleLogger;
23  
24  import java.io.ByteArrayOutputStream;
25  import java.io.PrintStream;
26  import java.util.concurrent.atomic.AtomicBoolean;
27  
28  /**
29   * Specifies the strategy of scheduling whether sequential, or parallel.
30   * The strategy may use a thread pool <em>shared</em> with other strategies.
31   * <p/>
32   * One instance of strategy can be used just by one {@link Scheduler}.
33   * <p/>
34   * The strategy is scheduling tasks in {@link #schedule(Runnable)} and awaiting them
35   * completed in {@link #finished()}. Both methods should be used in one thread.
36   *
37   * @author Tibor Digana (tibor17)
38   * @since 2.16
39   */
40  public abstract class SchedulingStrategy
41      implements Destroyable
42  {
43  
44      private final AtomicBoolean canSchedule = new AtomicBoolean( true );
45  
46      private final ConsoleLogger logger;
47  
48      protected SchedulingStrategy( ConsoleLogger logger )
49      {
50          this.logger = logger;
51      }
52  
53      /**
54       * Schedules tasks if {@link #canSchedule()}.
55       *
56       * @param task runnable to schedule in a thread pool or invoke
57       * @throws java.util.concurrent.RejectedExecutionException if <tt>task</tt>
58       *                                    cannot be scheduled for execution
59       * @throws NullPointerException       if <tt>task</tt> is <tt>null</tt>
60       * @see org.junit.runners.model.RunnerScheduler#schedule(Runnable)
61       * @see java.util.concurrent.Executor#execute(Runnable)
62       */
63      protected abstract void schedule( Runnable task );
64  
65      /**
66       * Waiting for scheduled tasks to finish.
67       * New tasks will not be scheduled by calling this method.
68       *
69       * @return <tt>true</tt> if successfully stopped the scheduler, else
70       *         <tt>false</tt> if already stopped (a <em>shared</em> thread
71       *         pool was shutdown externally).
72       * @throws InterruptedException if interrupted while waiting
73       *                              for scheduled tasks to finish
74       * @see org.junit.runners.model.RunnerScheduler#finished()
75       */
76      protected abstract boolean finished()
77          throws InterruptedException;
78  
79      /**
80       * Stops scheduling new tasks (e.g. by {@link java.util.concurrent.ExecutorService#shutdown()}
81       * on a private thread pool which cannot be <em>shared</em> with other strategy).
82       *
83       * @return <tt>true</tt> if successfully stopped the scheduler, else
84       *         <tt>false</tt> if already stopped (a <em>shared</em> thread
85       *         pool was shutdown externally).
86       * @see java.util.concurrent.ExecutorService#shutdown()
87       */
88      protected abstract boolean stop();
89  
90      /**
91       * Stops scheduling new tasks and <em>interrupts</em> running tasks
92       * (e.g. by {@link java.util.concurrent.ExecutorService#shutdownNow()} on a private thread pool
93       * which cannot be <em>shared</em> with other strategy).
94       * <p/>
95       * This method calls {@link #stop()} by default.
96       *
97       * @return <tt>true</tt> if successfully stopped the scheduler, else
98       *         <tt>false</tt> if already stopped (a <em>shared</em> thread
99       *         pool was shutdown externally).
100      * @see java.util.concurrent.ExecutorService#shutdownNow()
101      */
102     protected boolean stopNow()
103     {
104         return stop();
105     }
106 
107     /**
108      * Persistently disables this strategy. Atomically ignores {@link Balancer} to acquire a new permit.<p/>
109      * The method {@link #canSchedule()} atomically returns {@code false}.
110      * @return {@code true} if {@link #canSchedule()} has return {@code true} on the beginning of this method call.
111      */
112     protected boolean disable()
113     {
114         return canSchedule.getAndSet( false );
115     }
116 
117     protected void setDefaultShutdownHandler( Scheduler.ShutdownHandler handler )
118     {
119     }
120 
121     /**
122      * @return <tt>true</tt> if a thread pool associated with this strategy
123      *         can be shared with other strategies.
124      */
125     protected abstract boolean hasSharedThreadPool();
126 
127     /**
128      * @return <tt>true</tt> unless stopped, finished or disabled.
129      */
130     protected boolean canSchedule()
131     {
132         return canSchedule.get();
133     }
134 
135     protected void logQuietly( Throwable t )
136     {
137         ByteArrayOutputStream out = new ByteArrayOutputStream();
138         PrintStream stream = new PrintStream( out );
139         try
140         {
141             t.printStackTrace( stream );
142         }
143         finally
144         {
145             stream.close();
146         }
147         logger.info( out.toString() );
148     }
149 }